﻿using System;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Web.Mvc;
using CoreLibrary;
using CoreLibrary.Service;

using DataContractSerializer = CoreLibrary.JsonNet.DataContractSerializer;

namespace Web.Models.Common {

    public class JSONResponse : JsonResult {

        public const string JSONException = "JsonException";
        public HttpStatusCode StatusCode { get; set; }

        public JSONResponse(HttpStatusCode code, object data) {
            Data = data;
            StatusCode = code;
        }

        public static JSONResponse CreateResponse (object result) {
            return new JSONResponse(HttpStatusCode.OK, result);
        }

        public static JSONResponse CreateInternalError (string message) {
            return CreateError(new ServiceError(ErrorCode.ServerInternal, message));
        }

        public static JSONResponse CreateUnauthenticated (string message) {
            return CreateError(new ServiceError(ErrorCode.Unauthenticated, message));
        }

        public static JSONResponse CreateUnauthorised (string message) {
            return CreateError(new ServiceError(ErrorCode.Unauthorised, message));
        }

        public static JSONResponse CreateInvalidRequest (string message) {
            return CreateError(new ServiceError(ErrorCode.InvalidRequest, message));
        }

        public static JSONResponse CreateUnexpected (string message) {
            return CreateError(new ServiceError(ErrorCode.Unexpected, message));
        }

        private static JSONResponse CreateError (ServiceError error) {
            return new JSONResponse(HttpStatusCode.InternalServerError, new JSONExceptionResponse {
                ErrorDetail = error,
                ExceptionType = JSONException,
                Message = error == null ? "Unexpected Error." : Util.GetString(error.Message)
            });
        }

        public override void ExecuteResult (ControllerContext context) {
            try {
                context.HttpContext.Response.ContentEncoding = Encoding.UTF8;
                context.HttpContext.Response.StatusCode  = (int)StatusCode;
                context.HttpContext.Response.ContentType = "application/json";
                context.HttpContext.Response.Write(DataContractSerializer.Serialize(Data));
            } 
            catch (Exception exception) {
                context.HttpContext.Response.StatusCode  = (int)HttpStatusCode.InternalServerError;
                context.HttpContext.Response.ContentType = "application/json";
                context.HttpContext.Response.Write(
                    DataContractSerializer.Serialize(
                        new JSONExceptionResponse {
                            ErrorDetail = new ServiceError(ErrorCode.ServerInternal, exception.Message),
                            ExceptionType = JSONException,
                            Message = exception.Message
                        }
                    )
                );
            } 
            finally {
                context.HttpContext.Response.Flush();
                context.HttpContext.Response.End();
            }
        }

        [DataContract]
        public class JSONExceptionResponse {

            [DataMember]
            public ServiceError ErrorDetail { get; set; }

            [DataMember]
            public String ExceptionType { get; set; }

            [DataMember]
            public String Message { get; set; }

        }
    }
}